#pragma once
#include <BasisObj.h>
#include <ITraverse.h>
#include <Logger.h>
#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/foreach.hpp>
#include <LA/Vec3.h>
#include <Frustum.h>

namespace grflib
{
    namespace engine
    {
        namespace core
        {
            template<typename TObj, typename TRenderQueue> //for ex. render_queue_obj_type
            HRESULT TraverseRenderQueue(IRenderFunc<TObj> &func, 
                TRenderQueue &renderQueue)
            {
                HRESULT hr = S_OK;
                BOOST_FOREACH(typename TRenderQueue::value_type &pObj, renderQueue)
                {
                    func.SetWorldMatPtr(&(pObj.second));
                    V_RETURN( func(pObj.first) );
                }
                return hr;
            }

            class CCamera;

            ///////////////////////////////////////////////////////////////
            // Abstraction for different scene graphs, ex. Octree, KD-tree
            template<typename TObj, typename TRenderQueue>
            class CSceneGraph : private boost::noncopyable
            {
            public:
				explicit CSceneGraph(void) {};
                virtual ~CSceneGraph(void) { Clear(); }

                //add object to scene graph
                virtual bool AddObj(boost::shared_ptr<TObj> &pObj) = 0;

                //remove an object from scene graph
                virtual void RemoveObj(boost::shared_ptr<TObj> &pObj) = 0;

                //remove all objects from scene graph
                virtual void Clear(void) {}

                virtual void NotifySceneUpdate(void) = 0;

                //update tree (ex. rebuild octree)
                virtual void Update(void) = 0;

                //generate rendering queue according to viewer/obj positions
                virtual void GenerateRenderQueue(TRenderQueue &renderQueue, 
                                                 const D3DXMATRIX *pViewMat,
                                                 const D3DXMATRIX *pProjMat) = 0;

                virtual boost::shared_ptr<TObj> GetIntersectedObj(const float3& src, const float3& dir) = 0;

                //traverse interface
                virtual HRESULT Traverse(const IMemberCaller<TObj>& func) = 0;
                //virtual HRESULT Traverse(const IMemberPtrCaller<TObj>& func) = 0;
            };
        } // namespace core
    }
}